/*
    作者：zx
    时间：2023.2.10
    描述：使用MBR模式管理磁盘

    ● MBR简介：https://wiki.osdev.org/MBR_(x86)
    ● MBR中分区表的格式：https://wiki.osdev.org/Partition_Table
*/

#ifndef DISK_H
#define DISK_H

#include "comm/types.h"
#include "cpu/irq.h"
#include "ipc/mutex.h"
#include "ipc/semaphore.h"

#define DISK_NAME_SIZE 32
#define DISK_PART_NAME_SIZE 32
#define DISK_PRIMARY_PART_COUNT (4+1)
#define DISK_TABLE_SIZE 2
// 主总线上磁盘的数量
#define DISK_PER_CHANNEL 2  

// 磁盘控制端口
#define DISK_IOBASE_PRIMARY 0x1F0
// 磁盘相关寄存器   
#define DISK_DATA(disk) (disk->port_base + 0)
#define DISK_ERROR(disk) (disk->port_base + 1)
#define DISK_SECTOR_COUNT(disk) (disk->port_base + 2)
#define DISK_LBA_L0(disk) (disk->port_base + 3)
#define DISK_LBA_MID(disk) (disk->port_base + 4)
#define DISK_LBA_HI(disk) (disk->port_base + 5)
#define DISK_DRIVE(disk) (disk->port_base + 6)          // 磁盘drive类型(LBA)
#define DISK_STATUS(disk) (disk->port_base + 7)
#define DISK_CMD(disk) (disk->port_base + 7)

// 设置0x1F6寄存器为LBA模式，其高三位都为1
#define DISK_DRIVE_BASE 0xE0

// 磁盘状态
#define DISK_STATUS_ERR (1 << 1)
#define DISK_STATUS_DRQ (1 << 3)            // 就绪状态，是否可读写文件
#define DISK_STATUS_DF  (1 << 5)      
#define DISK_STATUS_BSY (1 << 7)            // 忙状态

// 磁盘命令
#define DISK_CMD_IDENTIFY 0xEC
#define DISK_CMD_READ 0x24
#define DISK_CMD_WRITE 0x34          

#pragma pack(1)
// MBR一个磁盘有4个分区
#define MBR_PRIMARY_PART_COUNT 4
// 分区表的格式
typedef struct _part_item_t
{
    uint8_t boot_active;
    uint8_t start_header;
    uint16_t start_sector : 6;
    uint16_t start_cylinder: 10;    // 磁道
    uint8_t system_id;              // 文件系统类型
    uint8_t end_header;
    uint16_t end_sector : 6;
    uint16_t end_cylinder : 10;
    uint32_t relative_sector;      // LBA模式的相对扇区号，也是起始扇区    
    uint32_t total_sectors;

}part_item_t;

// MBR磁盘管理方式，用于第一个扇区
typedef struct _mbr_t
{
    // 第一个扇区前446个字节用于引导代码
    uint8_t code[446];
    // 4个16字节的分区表项，共64字节
    part_item_t part_item[MBR_PRIMARY_PART_COUNT];
    // 最后两字节0x55 0xAA
    uint8_t boot_sign[2];
}mbr_t;
#pragma pack()

struct _disk_t;
typedef struct _partinfo_t
{
    char name[DISK_PART_NAME_SIZE];
    struct _disk_t * disk;
    int start_sector;
    int total_sector_count;
    enum{
        FS_INVALID = 0x00,
        FS_FAT16_0 = 0x6,
        FS_FAT16_1 = 0xE,
    }type;
}partinfo_t;
 
typedef struct _disk_t
{
    char name[DISK_NAME_SIZE];
    int sector_size;                // 扇区大小
    int sector_count;               // 扇区数量

    // 驱动器号，用于设置DISK_DRIVE寄存器
    enum{
        DISK_MASTER = (0 << 4),                // 磁盘
        DISK_SLAVE = (1 << 4),
    }drive;
    uint16_t port_base;             // 硬件起始端口

    // 本来应该只有4个分区，多添加一个表项用于管理MBR
    partinfo_t partinfo[DISK_PRIMARY_PART_COUNT];           

    mutex_t * mutex;
    semaphore_t * operate_sema;
}disk_t;

void exception_handler_disk_primary(void);
void disk_init(void);
void do_handler_disk_primary(exception_frame_t *);
#endif // !DISK_H
